import React, { Component } from "react";
import global from "@/global/config.js"; //我感觉没有必要吧这个参数拆出来--不好复用
import "./index.scss";
// antd
import {
  Form,
  Input,
  Button,
  InputNumber,
  Radio,
  Select,
  DatePicker,
  Row,
  Col,
} from "antd";
// propTypes
import PropTypes from "prop-types";
import "moment/locale/zh-cn";
import locale from "antd/es/date-picker/locale/zh_CN";
// 组件
import SelectComp from "../select/Index"; //多选
import UploadComp from "components/upload/Index.js"; //图片上传
import Editor from "components/Editor/Index.js"; //富文本
const { Option } = Select;
class FormCom extends Component {
  constructor(props) {
    super(props);
    this.form = React.createRef()
    this.state = {
      mesPreix: {
        Input: "请输入",
        Radio: "请选择",
        Select: "请选择",
        Date: "请选择",
        Upload: "请上传",
        TextArea: "请输入",
      },
      isEdit: false,
      $this: this,
    };
  }
  onFinish = (val) => {
    // 这个submit用来外面执行，外面将获得两个参数一个是表单的值，另一个是表单的dom用来重置表单用的/或者触发表单验证validateFields
    this.props.submit(val, this.form.current);
  };

  // 初始化
  initFormItem = () => {
    const { formItem } = this.props;
    // 检验是否存在
    if (!formItem || (formItem && formItem.length === 0)) {
      return;
    }
    // 循环处理
    return formItem.map((item) => this.createControl(item));
  };
  //
  createControl = (item) => {
    let elem = null;
    switch (item.type) {
      case "Input":
        elem = this.inputElem(item);
        break;
      case "Select":
        elem = this.selectElem(item);
        break;
      case "SelectComponent":
        elem = this.SelectComponent(item);
        break;
      case "InputNumber":
        elem = this.inputNumberElem(item);
        break;
      case "Radio":
        elem = this.radioElem(item);
        break;
      case "Slot":
        elem = this.slotElem(item);
        break;
      case "Column":
        elem = this.columnElem(item);
        break;
      case "Date":
        elem = this.dateElem(item);
        break;
      case "Upload":
        elem = this.uploadElem(item);
        break;
      case "TextArea":
        elem = this.textAreaElem(item);
        break;
      case "Editor":
        elem = this.editorElem(item);
        break;
      case "formItemInline":
        elem = this.formItemInlineElem(item);
        break;
      default:
        break;
    }
    return elem;
  };
  // 规则
  rules = (data) => {
    let rulesAry = [];
    const { required, message, rules, label, type } = data;
    const { mesPreix } = this.state;
    if (required) {
      let messages = message || `${mesPreix[type]}${label}`;
      rulesAry.push({ required: true, message: messages });
    }
    if (rules && rules.length > 0) {
      rulesAry = [...rulesAry, ...rules];
    }
    return rulesAry;
  };
  // 生命周期
  static getDerivedStateFromProps({ editData }, state) {
    if (Object.keys(editData).length > 0) {
      state.$this.refs["form"] &&
        state.$this.refs["form"].setFieldsValue(editData);
      return {
        isEdit: true,
      };
    }
    return null;
  }
  // 渲染
  inputElem = (data) => {
    const { label, name, style, placeholder } = data;
    const rules = this.rules(data);
    return (
      <Form.Item label={label} name={name} key={name} rules={rules}>
        <Input style={style} placeholder={placeholder} />
      </Form.Item>
    );
  };
  textAreaElem = (data) => {
    const { label, name, style, placeholder } = data;
    const rules = this.rules(data);
    return (
      <Form.Item label={label} name={name} key={name} rules={rules}>
        <Input.TextArea style={style} placeholder={placeholder} />
      </Form.Item>
    );
  };
  selectElem = (data) => {
    const { label, name, options, style, placeholder } = data;
    const rules = this.rules(data);
    return (
      <Form.Item label={label} name={name} key={name} rules={rules}>
        <Select style={style} placeholder={placeholder}>
          {options === "status" &&
            global[options].map((elem) => {
              const { value, label } = elem;
              return (
                <Option key={value} value={value}>
                  {label}
                </Option>
              );
            })}
          {Array.isArray(options) &&
            options.map((elem) => {
              const { value, label } = elem;
              return (
                <Option key={value} value={value}>
                  {label}
                </Option>
              );
            })}
        </Select>
      </Form.Item>
    );
  };
  inputNumberElem = (data) => {
    const { label, name, style, min, max } = data;
    const rules = this.rules(data);
    return (
      <Form.Item label={label} name={name} key={name} rules={rules}>
        <InputNumber min={min} max={max} style={style} />
      </Form.Item>
    );
  };
  radioElem = (data) => {
    const { label, name, options, style, placeholder } = data;
    const rules = this.rules(data);
    return (
      <Form.Item label={label} name={name} key={name} rules={rules}>
        <Radio.Group style={style} placeholder={placeholder}>
          {options &&
            options.map((elem) => {
              const { value, label } = elem;
              return (
                <Radio key={value} value={value}>
                  {label}
                </Radio>
              );
            })}
        </Radio.Group>
      </Form.Item>
    );
  };

  SelectComponent = (data) => {
    // 这里结合了SelectComponent一起封装的
    const { label, name, url, style, options = [], propsKey = {} } = data;
    const rules = this.rules(data);
    return (
      // 要注意哪些参数是传给label 哪些是传给selectComp---后续考虑是不是有必要吧Form.Item封装到一起？  ---SelectComp这个可以通过onChange知道拿到val
      // 自定义规则没做 rules={...rules,...xx}
      <Form.Item label={label} name={name} key={name} rules={rules}>
        <SelectComp
          style={style}
          url={url}
          options={options}
          propsKey={propsKey}
        ></SelectComp>
      </Form.Item>
    );
  };
  slotElem = (data) => {
    // ps 如果外面用到插槽（里面无法满足的情况） 那么不能通过直接set表单获取数据，重置数据，以及编辑渲染时手动将对于的数据渲染上，需要吧数据在外面单独定义，里面抛出一些数据手动的根据情况来处理(能做，但是会麻烦很多--万不得已建议少用)
    const { label, name, slotName } = data;
    const rules = this.rules(data);
    return (
      <Form.Item label={label} key={name} rules={rules}>
        {this.props.children && Array.isArray(this.props.children)
          ? this.props.children.filter((elem) => elem.props.slot_name === slotName)
          : this.props.children}
      </Form.Item>
    );
  };
  columnElem = (data) => {
    const { label, className } = data;
    // 栏目名称
    return (
      <div className={className} key={label}>
        <h4>{label}</h4>
      </div>
    );
  };
  dateElem = (data) => {
    const { label, name, picker, style, format } = data;
    const rules = this.rules(data);
    return (
      <Form.Item label={label} name={name} key={name} rules={rules}>
        <DatePicker
          locale={locale}
          style={style}
          picker={picker}
          format={format}
          // 日期这里拿到的是标准国际日期 md--传的时候需要自己转一次
        ></DatePicker>
      </Form.Item>
    );
  };
  uploadElem = (data) => {
    const { label, name, style } = data;
    const rules = this.rules(data);
    return (
      <Form.Item label={label} name={name} key={name} rules={rules}>
        <UploadComp name={name} style={style}></UploadComp>
      </Form.Item>
    );
  };
  editorElem = (data) => {
    const { label, name, style } = data;
    const rules = this.rules(data);
    return (
      <Form.Item label={label} name={name} key={name} rules={rules}>
        <Editor name={name} style={style}></Editor>
      </Form.Item>
    );
  };
  formItemInlineElem = (data) => {
    // label 左侧名字 col_label左侧占的位置(栅格24) 和外面项一样的结构--是个数组inline_item
    const { label, col_label = 2, col_control = 22, inline_formItem } = data;
    const rules = this.rules(data);
    return (
      <Row key={label}>
        {/* 左侧名字--里面的部分样式需要重写-还需要在以前的基础上去拿 */}
        <Col
          span={col_label}
          className="ant-form-item"
          style={{ textAlign: "right" }}
        >
          <div className="ant-form-item-label">
            <label
              // for="name"
              className={
                rules.length > 0 && rules[0].required
                  ? "ant-form-item-required"
                  : ""
              }
            >
              {label}
            </label>
          </div>
        </Col>
        {/* 右侧：右侧又可以调用多个form组件 */}
        <Col span={col_control}>
          <Row>
            {inline_formItem &&
              inline_formItem.map((elem) => {
                const { name, col } = elem;
                return (
                  <Col
                    className="form-item-inline-control"
                    key={name}
                    span={col}
                  >
                    {this.createControl(elem)}
                  </Col>
                );
              })}
          </Row>
        </Col>
      </Row>
    );
  };

  render() {
    let { formLayout, initialValues, isShowBtn } = this.props;
    const { isEdit } = this.state;
    return (
      <Form
        {...formLayout}
        onFinish={this.onFinish}
        ref={this.form}
        initialValues={initialValues}
      >
        {this.initFormItem()}
        <Form.Item>
          {isShowBtn ? (
            <Button htmlType="submit" type="primary">
              {isEdit ? "修改" : "添加"}
            </Button>
          ) : null}
        </Form.Item>
      </Form>
    );
  }
}
//formItem需要渲染的input formLayout布局 submit确定按钮  editData编辑的参数 initialValues初始值
// 校验数据类型
FormCom.propTypes = {
  editData: PropTypes.object,
  formLayout: PropTypes.object,
  formItem: PropTypes.array,
  submit: PropTypes.func,
  initialValues: PropTypes.object,
  isShowBtn: PropTypes.bool,
};
// 默认
FormCom.defaultProps = {
  editData: {},
  formLayout: {},
  formItem: {},
  initialValues: {},
  isShowBtn: true,
};
export default FormCom;
//格式
// formLayout: {
//   labelCol: { span: 2 },
//   wrapperCol: { span: 22 }
// },
// formItem: [
//   {
//     type: "Column",
//     label: "个人信息",
//     className: "staffTitle"
//   },{
//   type: "Radio",
//   label: "性别",
//   name: "sex",
//   required: true,
//   style: { width: "250px" },
//   options: [
//     { label: "男", value: true },
//     { label: "女", value: false }
//   ],
// rules: [
//   ({ getFieldValue }) => ({
//     validator(rule, value) {
//       if (value && validatePeople(value)) {
//         return Promise.reject("请输入正确身份证号码！");
//       }
//       return Promise.resolve();
//     }
//   })
// ]
// },]
//   initialValues: { sex: true },键为name名字
// key作为索引 不能一样不然报错 搞一开始测试的时候注意检查--一般都要传name label字段 因为key是根据他们来搞的 --应该考虑直接用索引

// { 内联的
//   type: "formItemInline",
//   label: "xx",
//   col_label:2,
//   col_control:22,
//   inline_formItem:[ 这里面 就是传formItem里面那些针对的一样有多个formItem选项的 ]
// },
